<?php
declare (strict_types=1);

namespace app\course\logic\base;

use app\admin\logic\system\Config as SystemConfig;
use app\common\exception\LogicException;
use app\common\logic\Attach;
use app\course\logic\base\admin\CourseCertConfig as CertConf;
use app\course\logic\classes\ClassesLink;
use app\course\model\base\CourseCert as CourseCertModel;
use app\course\model\record\LearnCourseFinished as Finished;
use app\exam\logic\PaperAnswer as Record;
use app\school\logic\school\School;
use Exception;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

/**
 * 课程证书类
 * Author 亓官雨树<lucky.max@foxmail.com>
 * Date 2021-10-11
 * @method whereCourseId(int $courseId)
 */
class CourseCert extends CourseCertModel
{

    /**
     * 证书生成
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 23/07/19
     *
     * @param int $courseId
     * @param int $mid
     * @return string|void
     * @throws Exception
     */
    public function addCert(int $courseId = 0, int $mid = 0)
    {
        // 证书发放配置
        $conf = app(CertConf::class)->getCertConfigByCourseId($courseId);
        if ($conf->isEmpty() || !$conf->has_cert) return '证书未配置发放';// return '(.*)'; Db::name('test')->save(['msg'=>'$1']);
        // 是否检测课程完结
        $checkFinished = intval($conf->course_is_finished);
        // 课程
        $course = app(Course::class)->findOrEmpty($courseId);
        // 课程未完结
        if ($checkFinished && $course->update_status) return '课程未完结';//Db::name('test')->save(['msg'=>'课程未完结']);
        // 学完课程和通过考试
        $doneCourse = in_array('1', $conf->condition);
        $passExam   = in_array('2', $conf->condition);
        // 查询课程考试
        if ($passExam) {
            $ids = strval($courseId);
            // if ( $course->course_type == 4 ) {
            //     $ids = app(ClassesLink::class)->getCourseIds($ids);
            // }
            $exams = app(CourseExamLink::class)->getCourseExams($ids);
        }
        // 查询满足条件的学员
        $mod = app(CourseStudent::class)->field('user_id')->whereCourseId($courseId)->whereRaw('expire_time >' . time() . ' OR expire_time is null');

        $stu = $mid ? $mod->whereUserId($mid)->column('user_id') : $mod->column('user_id');
        $sql = $mod->buildSql();
        // 当前已发
        $has = $this->whereRaw('user_id IN ' . $sql)->whereCourseId($courseId)->column('user_id');
        // 当前未颁发证书的学员
        $stu  = array_values(array_diff($stu, $has));
        $need = [];
        if (!count($stu)) return '无学员需要发放证书';//Db::name('test')->save(['msg'=>'无学员需要发放证书']);
        // 只需完成课程学习
        if (!$passExam) {
            $need = app(Finished::class)->getFinishedStu($courseId, $stu);
        } else {
            // 只需考试 // 两者必须
            if ($exams->isEmpty()) return '课程无考试';// Db::name('test')->save(['msg'=>'课程无考试']);
            if ($doneCourse) {
                $stu = app(Finished::class)->getFinishedStu($courseId, $stu);
            }
            foreach ($stu as $user) {
                // 学员全部通过考试
                $pass = $this->passAllCourseExamStatus($user, $exams);
                if ($pass) $need[] = $user;
            }
        }
        if (count($need)) {
            // 创建批量数据
            $save = [];
            foreach ($need as $user) {
                $save[] = [
                    'user_id'   => $user,
                    'course_id' => $courseId,
                    'code'      => '97' . crc32($user . $courseId . time())
                ];
            }
            $re = $this->saveAll($save);
            if ($re->isEmpty()) throw new LogicException('证书生成失败');
        }
    }

    /**
     * 通过所有的课程考试 状态
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-10-13
     *
     * @param  [type] $user  [description]
     * @param  [type] $exams [description]
     */
    public function passAllCourseExamStatus($user, $exams): bool
    {
        $raw   = '';
        $count = count($exams);
        foreach ($exams as $exam) {
            $raw .= "( user_id=$user AND rollup_id=0 AND paper_id=" . $exam->paper_id . ' AND user_score >= ' . $exam->pass_score . ' ) OR ';
        }
        $raw = trim($raw, ' OR');
        $num = app(Record::class)->whereRaw($raw)->group('paper_id')->count();

        // return $num;
        return !($num < $count);
    }

    /**
     * 获取我的证书列表数据
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 22/12/21
     *
     * @param $param
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getMyCert($param)
    {

        $title     = $param['title'] ?? '';
        $startTime = $param['start_time'] ?? 0;
        $endTime   = $param['end_time'] ?? 0;
        $map[]     = ['course_cert.user_id', '=', request()->mid];
        if ($title) $map[] = ['course.title', 'like', '%' . $title . '%'];
        if ($startTime) $map[] = ['course_cert.create_time', '>', $startTime];
        if ($endTime) $map[] = ['course_cert.create_time', '<', $endTime];

        $certInfo = $this->getCertConf();
        return $this->withJoin('course')->where($map)->select()
            ->each(function ($i) use ($certInfo) {
                $i->cert_title = str_replace('{{course_title}}', $i->course_title, $certInfo['title']);
                $i->mhm        = app(School::class)->where('id', $i->course->mhm_id)->value('title');
            })->hidden(['course', 'course_type']);

        // return $this->withJoin('course')->where($map)->select()
        //     ->each(function ($i) {
        //         $certInfo      = $this->getCertConf($i->course->mhm_id);
        //         $i->cert_title = str_replace('{{course_title}}', $i->course_title, $certInfo['title']);
        //         $i->mhm        = app(School::class)->where('id', $i->course->mhm_id)->value('title');
        //     })->hidden(['course', 'course_type']);
    }

    /**
     * 证书详情
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 22/12/21
     *
     * @param $param
     * @return CourseCert|array|Model
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getCertDetail($param)
    {
        $id       = $param['id'] ?? 0;
        $info     = $this->field('id,user_id,course_id,create_time')->with(['nick_name', 'course'])->findOrFail($id);
        $certInfo = $this->getCertConf();

        if ($info->course_type == 4) {
            // 班级课,查询课程名称
            // 获取所有课程名称
            $certInfo['show_sections'] && $info->course_list = app(ClassesLink::class)->where('classes_id', $info->course_id)
                ->with(['course_title'])->select()->visible(['course_id', 'title']);
            // 班级课所有课程
            $ids              = app(ClassesLink::class)->where('classes_id', $info->course_id)->field('course_id')->buildSql();
            $info->class_hour = app(CourseSection::class)->whereRaw('course_id IN ' . $ids)->where('is_last', 1)->sum('class_hour');
        } else {
            // 查询第一级课时名称
            $certInfo['show_sections'] && $info->course_list = app(CourseSection::class)->where('course_id', $info->course_id)
                ->where('pid', 0)->order('create_time', 'ASC')->field('title')->select();
            $info->class_hour = app(CourseSection::class)->where('course_id', $info->course_id)->where('is_last', 1)->sum('class_hour');
        }
        // 标题替换
        $certInfo['title'] = str_replace('{{course_title}}', $info['course_title'], $certInfo['title']);
        // 内容替换
        $certInfo['content'] = str_replace(['{{nick_name}}', '{{date}}', '{{course_title}}', '{{finished_class_hour}}'], [$info['nick_name'], date('Y-m-d H:m', $info['create_time']), $info['course_title'], $info['class_hour']], $certInfo['content']);
        // 公章地址
        if ($certInfo['official_seal']) {
            $certInfo['official_seal_url']    = app(Attach::class)->where('id', $certInfo['official_seal'])->findOrEmpty()->getAttr('fileurl');
            $certInfo['official_seal_base64'] = $this->imgtobase64($certInfo['official_seal_url']);
        }
        // 背景地址
        if ($certInfo['background'] ?? 0) {
            $certInfo['background_url']    = app(Attach::class)->where('id', $certInfo['background'])->findOrEmpty()->getAttr('fileurl');
            $certInfo['background_base64'] = $this->imgtobase64($certInfo['background_url']);
        }

        $info['cert_info'] = $certInfo;

        return $info;
    }

    public function getCertConf(int $mhmId = 0)
    {
        $mhmId = $mhmId ?: request()->mhm_id;
        return SystemConfig::get(
            'course.cert.config',
            ['show_sections' => 0, 'official_seal' => 0, 'background' => 0, 'title' => '', 'content' => '', 'official_seal_place' => 'none'],
            $mhmId);
    }

    /**
     * 把网络图片图片转成base64
     * Author: 亓官雨树 <lucky.max@foxmail.com>
     * Date: 22/06/24
     *
     * @param string $img 图片地址
     * @return string
     */
    public function imgtobase64(string $img = ''): string
    {
        $imageInfo = getimagesize($img);

        return 'data:' . $imageInfo['mime'] . ';base64,' . chunk_split(base64_encode(file_get_contents($img)));
    }

}
